package com.bear.atlassianmcp.oauth.context;

import com.bear.atlassianmcp.oauth.model.OAuthRequestContext;
import com.bear.atlassianmcp.oauth.strategy.AuthenticationStrategy.ServiceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * OAuth 上下文持有者
 * 使用 ThreadLocal 存储当前线程的 OAuth 请求上下文信息
 */
public class OAuthContextHolder {
    
    private static final Logger logger = LoggerFactory.getLogger(OAuthContextHolder.class);
    
    /**
     * 线程本地存储的 OAuth 请求上下文
     */
    private static final ThreadLocal<OAuthRequestContext> contextHolder = new ThreadLocal<>();
    
    /**
     * 设置当前线程的 OAuth 请求上下文
     * 
     * @param context OAuth 请求上下文
     */
    public static void setContext(OAuthRequestContext context) {
        if (context != null) {
            logger.debug("Setting OAuth context for thread {}: {}", 
                        Thread.currentThread().getName(), context);
            contextHolder.set(context);
        } else {
            logger.debug("Clearing OAuth context for thread {}", Thread.currentThread().getName());
            contextHolder.remove();
        }
    }
    
    /**
     * 获取当前线程的 OAuth 请求上下文
     * 
     * @return OAuth 请求上下文，如果没有设置则返回 null
     */
    public static OAuthRequestContext getContext() {
        return contextHolder.get();
    }
    
    /**
     * 清除当前线程的 OAuth 请求上下文
     */
    public static void clearContext() {
        logger.debug("Clearing OAuth context for thread {}", Thread.currentThread().getName());
        contextHolder.remove();
    }
    
    /**
     * 检查当前线程是否有 OAuth 请求上下文
     * 
     * @return 如果有上下文返回 true，否则返回 false
     */
    public static boolean hasContext() {
        return contextHolder.get() != null;
    }
    
    /**
     * 获取当前上下文的服务类型
     * 
     * @return 服务类型，如果没有上下文或服务类型未设置则返回 null
     */
    public static ServiceType getServiceType() {
        OAuthRequestContext context = getContext();
        return context != null ? context.getServiceType() : null;
    }
    
    /**
     * 获取当前上下文的请求 URL
     * 
     * @return 请求 URL，如果没有上下文或 URL 未设置则返回 null
     */
    public static String getRequestUrl() {
        OAuthRequestContext context = getContext();
        return context != null ? context.getRequestUrl() : null;
    }
    
    /**
     * 获取当前上下文的 HTTP 方法
     * 
     * @return HTTP 方法，如果没有上下文则返回 "GET"
     */
    public static String getHttpMethod() {
        OAuthRequestContext context = getContext();
        return context != null ? context.getHttpMethod() : "GET";
    }
    
    /**
     * 创建并设置 OAuth 请求上下文的便捷方法
     * 
     * @param serviceType 服务类型
     * @param requestUrl 请求 URL
     * @param httpMethod HTTP 方法
     */
    public static void setContext(ServiceType serviceType, String requestUrl, String httpMethod) {
        OAuthRequestContext context = OAuthRequestContext.builder()
                .serviceType(serviceType)
                .requestUrl(requestUrl)
                .httpMethod(httpMethod)
                .build();
        setContext(context);
    }
    
    /**
     * 在指定的上下文中执行操作
     * 操作完成后自动清理上下文
     * 
     * @param context OAuth 请求上下文
     * @param operation 要执行的操作
     * @param <T> 操作返回类型
     * @return 操作结果
     */
    public static <T> T executeWithContext(OAuthRequestContext context, ContextOperation<T> operation) {
        OAuthRequestContext previousContext = getContext();
        try {
            setContext(context);
            return operation.execute();
        } finally {
            if (previousContext != null) {
                setContext(previousContext);
            } else {
                clearContext();
            }
        }
    }
    
    /**
     * 在指定的上下文中执行操作（无返回值）
     * 操作完成后自动清理上下文
     * 
     * @param context OAuth 请求上下文
     * @param operation 要执行的操作
     */
    public static void executeWithContext(OAuthRequestContext context, VoidContextOperation operation) {
        executeWithContext(context, () -> {
            operation.execute();
            return null;
        });
    }
    
    /**
     * 上下文操作接口（有返回值）
     * 
     * @param <T> 返回类型
     */
    @FunctionalInterface
    public interface ContextOperation<T> {
        T execute();
    }
    
    /**
     * 上下文操作接口（无返回值）
     */
    @FunctionalInterface
    public interface VoidContextOperation {
        void execute();
    }
    
    /**
     * 获取当前上下文的调试信息
     * 
     * @return 调试信息字符串
     */
    public static String getContextDebugInfo() {
        OAuthRequestContext context = getContext();
        if (context == null) {
            return "No OAuth context set for thread " + Thread.currentThread().getName();
        }
        
        return String.format("OAuth context for thread %s: serviceType=%s, url=%s, method=%s", 
                           Thread.currentThread().getName(),
                           context.getServiceType(),
                           context.getRequestUrl(),
                           context.getHttpMethod());
    }
    
    /**
     * 创建测试连接的上下文
     * 
     * @param serviceType 服务类型
     * @param baseUrl 基础 URL
     * @return 测试连接的上下文
     */
    public static OAuthRequestContext createTestContext(ServiceType serviceType, String baseUrl) {
        String testUrl = baseUrl + "/rest/api/2/myself";
        return OAuthRequestContext.builder()
                .serviceType(serviceType)
                .requestUrl(testUrl)
                .httpMethod("GET")
                .testConnection(true)
                .build();
    }
    
    /**
     * 从当前上下文推断服务类型
     * 如果上下文中没有明确设置服务类型，尝试从 URL 推断
     * 
     * @param fallbackServiceType 如果无法推断时使用的默认服务类型
     * @return 推断的服务类型
     */
    public static ServiceType inferServiceType(ServiceType fallbackServiceType) {
        OAuthRequestContext context = getContext();
        if (context == null) {
            return fallbackServiceType;
        }
        
        // 如果上下文中已经设置了服务类型，直接返回
        if (context.getServiceType() != null) {
            return context.getServiceType();
        }
        
        // 尝试从 URL 推断服务类型
        String requestUrl = context.getRequestUrl();
        if (requestUrl != null) {
            String lowerUrl = requestUrl.toLowerCase();
            if (lowerUrl.contains("/wiki/") || lowerUrl.contains("confluence")) {
                return ServiceType.CONFLUENCE;
            } else if (lowerUrl.contains("jira") || lowerUrl.contains("/rest/api/")) {
                return ServiceType.JIRA;
            }
        }
        
        return fallbackServiceType;
    }
}
